﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using ICSharpCode.SharpZipLib.Zip;
using System.IO;
using BestHTTP;
using System;

public class VersionUpdateSystem : MonoSingleton<VersionUpdateSystem> {

	private class UpdateItem
	{
		public string fileName;

		public long size;

		public string md5;
	}

	public const string ZIP_FILE_NAME = "Asset.zip";

	private const int UNZIP_SIZE = 2097152;
    

    public delegate void OnVersionUpdateComplete();

	private enVersionUpdateState mUpdateState;

	private OnVersionUpdateComplete mOnVersionUpdateComplete;

	private float mProgress = 0f;

	private int ServerResVersion = 0;

	private List<UpdateItem> mUpdateItem = new List<UpdateItem> ();

	private long mDownloadSize = 0;

	private int mUpdateItemNum = 0;

	private List<DownloadTask> mDownloadTasks = new List<DownloadTask> ();

	private string CurVersionURL  {
		get {
			return AppConfig.MainURL + AppVersion.Version + "/" + AppVersion.CodeVersion;
		}
	}

	private string UpdatePath {
		get {
			string updatePath = FileTools.CombinePath (Application.persistentDataPath, "Update");
			if (!Directory.Exists (updatePath)) {
				Directory.CreateDirectory (updatePath);
			}
			return updatePath;
		}
	}

	string UpdateAssetBundlePath {
		get {
			string updatePath = FileTools.CombinePath (UpdatePath, "AssetBundles");
			if (!Directory.Exists (updatePath)) {
				Directory.CreateDirectory (updatePath);
			}
			return updatePath;
		}
	}

	protected override void Init ()
	{
		base.Init ();
		this.mUpdateState = enVersionUpdateState.None;

	}

	protected override void OnDestroy ()
	{
		StopCoroutine (StartUnZip());
		StopCoroutine (AndroidCopy());
		StopCoroutine (UnzipResFolder());
		base.OnDestroy ();
	}

	public void StartVersionUpdate(OnVersionUpdateComplete onVersionUpdateComplete) {
		this.mOnVersionUpdateComplete = onVersionUpdateComplete;
		this.mUpdateState = enVersionUpdateState.StartCheckPathPermission;
		//this.mUpdateState = enVersionUpdateState.Complete;
	}

	void Update() {
		switch(this.mUpdateState) {
		case enVersionUpdateState.StartCheckPathPermission:
			StartCheckPathPermission ();
			break;
		case enVersionUpdateState.StartUnzipResource:
			StartUnzipResource ();
			break;
		case enVersionUpdateState.StartCheckAppVersion:
			StartCheckAppVersion ();
			break;
		case enVersionUpdateState.StartCheckResourceVersion:
			StartCheckResVersion ();
			break;
		case enVersionUpdateState.StartDownloadResource:
			StartDownloadResource ();
			break;
		case enVersionUpdateState.DownloadResource:
			DownloadingResource ();
			break;
		case enVersionUpdateState.StartUnZipDownloadResource:
			StartUnzipDownloadResource ();
			break;

		case enVersionUpdateState.Complete:
			UpdateComplete ();
			break;
		}
	}

	private void UpdateUIProgress(string count, float progress) {
		EventBus.Instance.BroadCastEvent<float, string> (EventID.VERSION_UPDATE_PROGRESS_CHANGE, progress, count);
	}

	private void UpdateUIDes(string des) {
		EventBus.Instance.BroadCastEvent<string> (EventID.VERSION_UPDATE_DES_CHANGE, des);
	}

	void StartCheckPathPermission() {
		UpdateUIDes ("检测目录的读写权限！");
		this.mUpdateState = enVersionUpdateState.CheckPathPermission;
		if (!string.IsNullOrEmpty (Application.persistentDataPath)) {
			this.mUpdateState = enVersionUpdateState.StartUnzipResource;
		}
	}

	void StartUnzipResource() {
		if (FileTools.IsFileExist (ResourceManager.ResInfoFilePath)) {
			this.mUpdateState = enVersionUpdateState.StartCheckAppVersion;
		} else {
			this.mUpdateState = enVersionUpdateState.UnzipResource;
#if UNITY_ANDROID
			StartCoroutine(AndroidCopy());
#else
			StartCoroutine(StartUnZip());
#endif
		}
	}

	IEnumerator AndroidCopy() {
		UpdateUIDes ("开始复制文件！");
		string fromPath = FileTools.CombinePath (Application.streamingAssetsPath, ResourceManager.ASSETPATH);
		fromPath = FileTools.CombinePath (fromPath, ZIP_FILE_NAME);

		string toPath = FileTools.CombinePath (UpdatePath, ZIP_FILE_NAME);;

		UnityEngine.Networking.UnityWebRequest www = UnityEngine.Networking.UnityWebRequest.Get(fromPath);
		yield return www.SendWebRequest();
		if (File.Exists(toPath))  
		{  
			File.Delete(toPath);  
		}  
		FileStream fsDes = File.Create(toPath);  
		fsDes.Write(www.downloadHandler.data, 0, www.downloadHandler.data.Length);
		fsDes.Flush();  
		fsDes.Close();  

		StartCoroutine(StartUnZip());
	}

	IEnumerator StartUnZip() {
		UpdateUIDes ("开始解压文件！");
		this.mProgress = 0f;
#if UNITY_ANDROID
		string fromPath = UpdatePath;
#else
		string fromPath = FileTools.CombinePath (Application.streamingAssetsPath, ResourceManager.ASSETPATH);
#endif
		//string fromPath = FileTools.CombinePath (Application.streamingAssetsPath, ResourceManager.ASSETPATH);
		fromPath = FileTools.CombinePath (fromPath, ZIP_FILE_NAME);
		FileTools.CreateDirectory (ResourceManager.PersistentAssetPath);

		long allS = 0;
		using (ZipInputStream s = new ZipInputStream (File.OpenRead (fromPath))) {
			ZipEntry theEntry;
			while ((theEntry = s.GetNextEntry ()) != null) {
				allS += s.Length;
			}
		}

		using (ZipInputStream s = new ZipInputStream(File.OpenRead(fromPath))) {
			ZipEntry theEntry;
			long allSize = 0;

			while ((theEntry = s.GetNextEntry()) != null) {
				string fileName = Path.GetFileName(theEntry.Name);
				if (!string.IsNullOrEmpty(fileName)) {
					string toFilePath = ResourceManager.PersistentAssetPath + "/" + fileName;
					if (File.Exists(toFilePath)) {
						File.Delete(toFilePath);
					}
					using (FileStream streamWriter = File.Create(toFilePath)) {
						int size = UNZIP_SIZE;
						byte[] data = new byte[UNZIP_SIZE];
						while (true) {
							size = s.Read(data, 0, data.Length);
							if (size > 0) {
								streamWriter.Write(data, 0, size);
							} else {
								break;
							}
							allSize += size;
							this.mProgress = ((float)allSize) / allS;
							UpdateUIProgress(allSize + "/" + allS, this.mProgress);
							yield return null;
						}
					}
				}
			}
		}
		yield return null;

#if UNITY_ANDROID
		FileTools.DeleteFile(fromPath);
#endif

		if (FileTools.IsFileExist (ResourceManager.ResInfoFilePath)) {
			this.mUpdateState = enVersionUpdateState.StartCheckAppVersion;
		} else {
			Debug.LogError ("第一次解压资源出错！");
		}
	}

	void StartCheckAppVersion() {
        UpdateUIDes("检测版本！");
        AppVersion.Init ();
        if (Application.internetReachability == NetworkReachability.NotReachable)
        {
            this.mUpdateState = enVersionUpdateState.Complete;
        }
        else
        {
            this.mUpdateState = enVersionUpdateState.CheckAppVersion;
            CheckAppVersion();
        }
	}

	void CheckAppVersion() {
        Debug.Log(CurVersionURL + "/" + ResourceManager.RES_INFO_NAME);
		HTTPRequest versionRequest = new HTTPRequest(new System.Uri(CurVersionURL + "/" + ResourceManager.RES_INFO_NAME), HTTPMethods.Get, (req, resp) => {
			if (req.State == HTTPRequestStates.Finished && resp != null) {
				string text = resp.DataAsText.Trim();
                try {
                    ResourceInfo info = JsonUtility.FromJson<ResourceInfo>(text);
                    if (info.AppVersion != AppVersion.Version || info.CodeVersion != AppVersion.CodeVersion)
                    {
                        Debug.LogError("请下载最新版本的程序！");
                    }
                    else
                    {
                        Debug.Log("客户端版本:" + AppVersion.ToString() + "  服务器版本：" + info.AppVersion + "." + info.CodeVersion + "." + info.ResVersion);
                        if (info.ResVersion == AppVersion.ResVersion)
                        {
                            using (StreamWriter streamWriter = new StreamWriter(FileTools.CombinePath(UpdatePath, ResourceManager.RES_INFO_NAME), false))
                            {
                                streamWriter.WriteLine(text);
                                streamWriter.Flush();
                            }

                            Debug.Log("复制version文件！");
                            FileTools.CopyFile(FileTools.CombinePath(UpdatePath, ResourceManager.RES_INFO_NAME), ResourceManager.ResInfoFilePath);
                            AppVersion.Init();

                            this.mUpdateState = enVersionUpdateState.Complete;
                        }
                        else
                        {
                            ServerResVersion = info.ResVersion;
                            using (StreamWriter streamWriter = new StreamWriter(FileTools.CombinePath(UpdatePath, ResourceManager.RES_INFO_NAME), false))
                            {
                                streamWriter.WriteLine(text);
                                streamWriter.Flush();
                            }
                            this.mUpdateState = enVersionUpdateState.StartCheckResourceVersion;
                        }
                    }
                }
                catch
                {
                    Debug.LogError("解析版本文件失败！");
                    this.mUpdateState = enVersionUpdateState.Complete;
                }
				
			} else {
				Debug.LogError("获取版本资源出错！");
				this.mUpdateState = enVersionUpdateState.Complete;
			}
		});
		versionRequest.DisableCache = true;
		versionRequest.Send ();
	}

	void StartCheckResVersion() {
		UpdateUIDes ("检测资源大小！");
		this.mUpdateState = enVersionUpdateState.CheckResourceVersion;
		CheckResourceVersion ();
	}

	private void CheckResourceVersion() {
		HTTPRequest resourceRequest = new HTTPRequest(new System.Uri(CurVersionURL + "/" + ServerResVersion + "/" + ResourceManager.UPDATE_NAME), HTTPMethods.Get, (req, resp) => {
			if (req.State == HTTPRequestStates.Finished && resp != null) {
				string text = resp.DataAsText.Trim();
				List<UpdateItem> downItem = GetItemsFromTxt (text);
				byte[] curB = FileTools.ReadFile (FileTools.CombinePath(ResourceManager.PersistentAssetPath, ResourceManager.UPDATE_NAME));
				mDownloadSize = 0;
				using (StreamReader streamReader = new StreamReader (new MemoryStream (curB))) {
					List<UpdateItem> curItem = GetItemsFromTxt (streamReader.ReadToEnd ());
					mUpdateItem.Clear();
					for (int i = 0; i < downItem.Count; i++) {
						bool isHave = false;
						for (int j = 0; j < curItem.Count; j++) {
							if (downItem [i].fileName == curItem [j].fileName) {
								isHave = true;
								if (downItem [i].md5 != curItem [j].md5) {
									mUpdateItem.Add (downItem [i]);
									mDownloadSize += downItem [i].size;
								}
								break;
							}
						}
						if (!isHave) {
							mUpdateItem.Add (downItem [i]);
							mDownloadSize += downItem [i].size;
						}
					}
					string sizeF = String.Format ("{0:F}", mDownloadSize / (float)(1024*1024));
					Debug.Log(string.Format("需要下载{0}个文件，共{1}M。", mUpdateItem.Count, sizeF));
					using (StreamWriter streamWriter = new StreamWriter(FileTools.CombinePath(UpdatePath, "update.txt"), false)) {
						streamWriter.WriteLine(text);
						streamWriter.Flush();
					}

					this.mUpdateState = enVersionUpdateState.StartDownloadResource;
				}
			} else {
				Debug.LogError("获取资源更新文件出错！");
                this.mUpdateState = enVersionUpdateState.Complete;
            }
		});
		resourceRequest.DisableCache = true;
		resourceRequest.Send ();
	}

	private void StartDownloadResource() {
		UpdateUIDes ("开始下载资源！");
		this.mUpdateItemNum = this.mUpdateItem.Count;
		this.mUpdateState = enVersionUpdateState.DownloadResource;
		this.mDownloadTasks.Clear ();
		for (int i=0; i<this.mUpdateItemNum; i++) {
			DownloadResource (this.mUpdateItem [i]);
		}
	}

	private void DownloadResource(UpdateItem item) {
		DownloadTask task = new DownloadTask ();
		task.URL = CurVersionURL + "/" + ServerResVersion + "/" + item.fileName;
		task.SavePath = FileTools.CombinePath(UpdateAssetBundlePath, item.fileName);
		if (FileTools.IsFileExist(task.SavePath)) {
			FileTools.DeleteFile (task.SavePath);
		}
		task.Size = item.size;
        Debug.LogWarning(task.Size);
        task.OnProgress = new DownloadTask.OnProgressDelegate (delegate(long totalSize, long nowSize) {
			task.DownloadedSize = nowSize;
            Debug.Log(nowSize +","+ totalSize);
		});
		task.OnSuccess = delegate() {
			task.DownloadedSize = task.Size;
			Debug.LogWarning("下载完成！");	
		};
		task.OnError = delegate(string errorString) {
			Debug.LogError(errorString);	
		};
		DownloadManager.Instance.AddTask (task);
		this.mDownloadTasks.Add (task);
	}

	private void DownloadingResource() {
		long s = 0;
		for (int j = 0; j < this.mDownloadTasks.Count; j++) {
			s += this.mDownloadTasks[j].DownloadedSize;
		}
		float precent = (s / (float)mDownloadSize) * 100.0f;
		Debug.Log(precent.ToString("F2") + "%");
		UpdateUIProgress(precent.ToString("F2") + "%", s / (float)mDownloadSize);
		if (s == mDownloadSize) {
			this.mUpdateState = enVersionUpdateState.StartUnZipDownloadResource;
		}
	}

	private void StartUnzipDownloadResource() {
		Debug.Log ("开始解压下载的资源");
		UpdateUIDes ("开始解压下载的资源！");
		this.mUpdateState = enVersionUpdateState.UnzipDownloadResource;
		StartCoroutine (UnzipResFolder());

	}

	private void UpdateComplete() {
		UpdateUIDes ("更新完成，加载配置文件！");
		this.mUpdateState = enVersionUpdateState.End;
		ResourceManager.Instance.LoadResourcePackerInfoSet ();
//		Resource res = ResourceManager.Instance.GetResource ("character/10001/Actor", typeof(GameObject), enResourceType.ScenePrefab, false, false);
//		UnityEngine.Object.Instantiate (res.m_content as GameObject);

		//res = ResourceManager.Instance.GetResource ("ui/Cylinder", typeof(GameObject), enResourceType.Prefab, false, false);
		//UnityEngine.Object.Instantiate (res.m_content as GameObject);

		this.mOnVersionUpdateComplete ();
	}


	List<UpdateItem> GetItemsFromTxt(string text) {
		List<UpdateItem> items = new List<UpdateItem> ();
		List<string> updateList = StringUtils.Split (text, Environment.NewLine, true, true);
		for(int i=0; i<updateList.Count; i++) {
			List<string> file = StringUtils.Split (updateList [i], ";", true, true);
			if (file.Count == 3) {
				items.Add (new UpdateItem {
					fileName = file[0],
					size = GeneralUtils.ForceLong(file[1]),
					md5 = file[2],
				});
			} else {
				Debug.LogError ("update.txt文件有错误！");
			}
		}
		return items;
	}

	private IEnumerator UnzipResFolder() {
		string[] files = Directory.GetFiles(UpdateAssetBundlePath);
		for (int i=0; i<files.Length; i++) {
			string name = files[i].Replace("\\", "/");
			if (files[i].IndexOf (".meta") > 0)
				continue;
			using (ZipInputStream s = new ZipInputStream(File.OpenRead(name))) {
				ZipEntry theEntry;
				long allSize = 0;
				while ((theEntry = s.GetNextEntry()) != null) {
					allSize = 0;
					string fileName = Path.GetFileName(theEntry.Name);
					if (!string.IsNullOrEmpty(fileName)) {
						string toFilePath = ResourceManager.PersistentAssetPath + "/" + fileName;
						if (File.Exists(toFilePath)) {
							File.Delete(toFilePath);
						}
						using (FileStream streamWriter = File.Create(toFilePath)) {
							int size = UNZIP_SIZE;
							byte[] data = new byte[UNZIP_SIZE];
							while (true) {
								size = s.Read(data, 0, data.Length);
								if (size > 0) {
									streamWriter.Write(data, 0, size);
								} else {
									break;
								}
								allSize += size;
								this.mProgress = ((float)allSize) / s.Length;
								//Debug.LogError (this.mProgress);
								UpdateUIProgress(allSize + "/" + s.Length, this.mProgress);
								yield return null;
							}
						}
					}
				}
			}
		}
		Debug.Log ("解压完成！");
		FileTools.CopyFile (FileTools.CombinePath (UpdatePath, ResourceManager.RES_INFO_NAME), ResourceManager.ResInfoFilePath);
		Debug.Log ("复制version文件！");
		FileTools.CopyFile (FileTools.CombinePath (UpdatePath, ResourceManager.UPDATE_NAME), ResourceManager.UpdateFilePath);
		Debug.Log ("复制update文件！");
		FileTools.ClearDirectory (UpdatePath);
		this.mUpdateState = enVersionUpdateState.Complete;
	}
}
